2023-01-10-Line_Chart_with_Plotly¶

It is very easy to plot chart in plotly express!:)

Let's import the required libraries first:

In [1]:
# !pip3 install plotly
In [2]:
%%HTML
<script src="require.js"></script>
In [3]:
import pandas as pd
import plotly.express as px
import plotly.graph_objects as go
from plotly.offline import download_plotlyjs, init_notebook_mode, plot, iplot
init_notebook_mode(connected=False)

# import plotly.io as pio
# pio.renderers.default = "notebook"

# import plotly.offline as pyo
# Set notebook mode to work in offline https://www.pythonfixing.com/2021/11/fixed-plotly-chart-not-showing-in.html
# pyo.init_notebook_mode()
In [4]:
df = pd.DataFrame({"Date": ["2023-01-01", "2023-01-02", "2023-01-03", "2023-01-04", "2023-01-05", "2023-01-06", "2023-01-07", 
              "2023-01-08", "2023-01-09", "2023-01-10"],
     "Analysis": ["Normal", "Anomaly", "Normal", "Anomaly", "Anomaly", "Normal", "Normal", "Normal", "Normal", "Normal"],
     "Sales": [120, 30, 115, 10, 5, 100, 99, 123, 134, 96]})
In [5]:
df_with_group = pd.DataFrame({
    "Date": ["2023-01-01", "2023-01-02", "2023-01-03", "2023-01-04", "2023-01-05", "2023-01-06", "2023-01-07", 
             "2023-01-08", "2023-01-09", "2023-01-10", "2023-01-01", "2023-01-02", "2023-01-03", "2023-01-04", 
             "2023-01-05", "2023-01-06", "2023-01-07", "2023-01-08", "2023-01-09", "2023-01-10"],
    "Analysis": ["Normal", "Anomaly", "Normal", "Anomaly", "Anomaly", "Normal", "Normal", "Normal", "Normal", "Normal",
                 "Anomaly", "Normal", "Normal", "Anomaly", "Anomaly", "Normal", "Normal", "Normal", "Normal", "Anomaly"],
    "Sales": [120, 30, 115, 10, 5, 100, 99, 123, 134, 96, 
              15, 100, 103, 13, 8, 88, 111, 126, 120, 25],
    "Sales_Group": ["A", "A", "A", "A", "A", "A", "A", "A", "A", "A", "B", "B", "B", "B", "B", "B", "B", "B", "B", "B"]
})
In [6]:
df.Date = pd.to_datetime(df.Date)
df_with_group.Date = pd.to_datetime(df_with_group.Date)
In [7]:
df.head()
Out[7]:
Date Analysis Sales
0 2023-01-01 Normal 120
1 2023-01-02 Anomaly 30
2 2023-01-03 Normal 115
3 2023-01-04 Anomaly 10
4 2023-01-05 Anomaly 5
In [8]:
df_with_group.tail()
Out[8]:
Date Analysis Sales Sales_Group
15 2023-01-06 Normal 88 B
16 2023-01-07 Normal 111 B
17 2023-01-08 Normal 126 B
18 2023-01-09 Normal 120 B
19 2023-01-10 Anomaly 25 B

Here is a simple way to plot a animation chart!

In [9]:
fig = px.line(df, x="Date", y="Sales", title='Daily Sales')
fig.show(renderer='notebook')

And if we want to see 2 sales group's performance together:

In [10]:
fig2 = px.line(df_with_group, x="Date", y="Sales", color='Sales_Group', title='Daily Sales')
fig2.show()

Now it is time to markthe anomalies! We will use Graph objects for this. Start with mark the anomaly dates:

In [11]:
anomaly_date = df[df.Analysis == "Anomaly"]
anomaly_date
Out[11]:
Date Analysis Sales
1 2023-01-02 Anomaly 30
3 2023-01-04 Anomaly 10
4 2023-01-05 Anomaly 5
In [12]:
fig = px.line(df, x="Date", y="Sales", title='Daily Sales')
fig.add_traces(go.Scatter(x=anomaly_date["Date"], y=anomaly_date["Sales"], mode="markers", name="Anomaly", 
                          hoverinfo="skip"))
fig.show(renderer='notebook')

If you want to see the "Anomaly" at the chart, you should use "add_annotation":

In [13]:
fig = px.line(df, x="Date", y="Sales", title='Daily Sales')
fig.add_traces(go.Scatter(x=anomaly_date["Date"], y=anomaly_date["Sales"], mode="markers", name="Anomaly", 
                          hoverinfo="skip"))
for idx in range(len(anomaly_date)):
     fig.add_annotation(dict(font=dict(color='rgba(0,0,200,0.8)',size=12),
                                        x=anomaly_date["Date"].iloc[idx],
                                        y=anomaly_date["Sales"].iloc[idx],
                                        showarrow=False,
                                        text=anomaly_date["Analysis"].iloc[idx],
                                        textangle=0,
                                        xanchor='auto',  #['auto', 'left', 'center', 'right']
                                        xref="x",
                                        yref="y"))
fig.show(renderer='notebook')

And if we want to see 2 sales group's performance together:

In [14]:
# filter anomaly dates
anomaly_date_2 = df_with_group[df_with_group.Analysis == "Anomaly"]

# line plot
fig2 = px.line(df_with_group, x="Date", y="Sales", color='Sales_Group', title='Daily Sales')

# add marker
fig2.add_traces(go.Scatter(x=anomaly_date_2["Date"], y=anomaly_date_2["Sales"], mode="markers", name="Anomaly", 
                          hoverinfo="skip"))

# add annotation
for idx in range(len(anomaly_date_2)):
     fig2.add_annotation(dict(font=dict(color='rgba(0,0,200,0.8)',size=12),
                                        x=anomaly_date_2["Date"].iloc[idx],
                                        y=anomaly_date_2["Sales"].iloc[idx],
                                        showarrow=False,
                                        text=anomaly_date_2["Analysis"].iloc[idx],
                                        textangle=0,
                                        xanchor='auto',  #['auto', 'left', 'center', 'right']
                                        xref="x",
                                        yref="y"))

fig2.show(renderer='notebook')

References¶

  • https://stackoverflow.com/questions/64241461/plotly-how-to-add-markers-at-specific-points-in-plotly-line-graph-python-pan
  • https://stackoverflow.com/questions/68731627/plotly-express-line-chart-mark-specific-points-and-retain-hover-data
  • https://davistownsend.github.io/blog/PlotlyBloggingTutorial/
In [ ]:
!jupyter nbconvert --to html Line_Chart_with_Plotly.ipynb

front_matter_str = """--- layout: post title: 2023-01-10-Line_Chart_with_Plotly subtitle: I would like to explain the plotly express line chart and how to add marks to the chart. tags: [plotly,visulatisation] ---"""

import subprocess

def conv_nb_jekyll(filename,front_matter):

"""
this function will convert your jupyter notebook to html and 
prepend the front matter string you provide to the top of the resulting html file

Args:
    filename: filename of input jupyter notebook (.ipynb file)
    front_matter: python formatted string resembling YAML jekyll front matter
Returns:
    jekyll_html_post: location of final html file to post on your jekyll blog
"""

#convert jupyter notebook to html
subprocess.call(["jupyter", "nbconvert","--to","html","--template","full",filename])

#function that will prepend given string to given filename
def prepend_string(filename, string):
    with open(filename, 'r+') as f:
        content = f.read()
        f.seek(0, 0)
        f.write(string.rstrip('\r\n') + '\n' + content)

#call function to prepend front matter to the file 
html_file = filename.replace('.ipynb','.html')
prepend_string(html_file,front_matter)
print('converted html file at: ',html_file)

return html_file



jekyll_html_post = conv_nb_jekyll(filename='2023-01-10-Line_Chart_with_Plotly.ipynb',front_matter=front_matter_str)